package c2.cross.business.championrace.handler;

import c2.cross.business.championrace.ChampionRaceModule;
import cate.common.table.d.GDFight;
import cate.common.util.GameResult;
import cate.game.pvp.championrace.data.*;
import cate.game.pvp.championrace.timer.ChampionRaceTimerTask;
import cate.game.pvp.championrace.ChampionRaceSpecUtils;
import easy.java.practice.errorcode.EcResult;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.util.StringUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;


@Slf4j
public class ChampionRaceKoSettingHandler extends AbstractChampionRaceSettingHandler{
    @Getter
    @Setter
    private boolean running = false;

    @Getter
    private final LinkedList<ChampionRaceRecord> recordQueue = new LinkedList<>();

    private long currentPowerDiff = Long.MAX_VALUE;
    private ChampionRaceRecord betRecord;

    private final List<ChampionRaceRecord> nextRecordList = Lists.newArrayList();

    public ChampionRaceKoSettingHandler(ChampionRaceModule parent) {
        super(parent);
    }

    @Override
    public boolean runSettingFunction(ChampionRaceTimerTask.Setting setting) {
        boolean canChange = parent.canChangeSpec(setting, ChampionRaceSpecUtils.getKoFlag(setting));
        if (!canChange) {
            return true;
        }
        if (!isRunning()) {
            setRunning(true);
            recordQueue.addAll(query(setting));
        }
        boolean result = handleQueuedTask();
        if (result) {
            nextRecordList.forEach(e -> parent.addRecordData(e));
            nextRecordList.clear();
            if (Objects.nonNull(betRecord)) {
                betRecord.setBetRound(true);
                ChampionRacePs psA = parent.findPs(betRecord.getIdA());
                ChampionRacePs psB = parent.findPs(betRecord.getIdB());
                parent.addBetRecordData(ChampionRaceBetRecord.of(betRecord, psA, psB, betRecord.getWinner()));
                betRecord = null;
                currentPowerDiff = Long.MAX_VALUE;
            }
            parent.changeSpec(setting, ChampionRaceSpecUtils.getKoFlag(setting));
        }
        return result;
    }

    @Override
    public boolean isMatch(ChampionRaceTimerTask.Setting setting) {
        return ChampionRaceSpecUtils.isMatchKoSimulator(setting);
    }

    @Override
    public void run() {

    }

    private List<ChampionRaceRecord> query(ChampionRaceTimerTask.Setting setting) {
        List<ChampionRaceRecord> recordList = Lists.newArrayList();
        ChampionRaceSpec spec = setting.getSpec();
        for (byte i = 0; i < 8; i++) {
            ChampionRaceSpec querySpec = ChampionRaceSpec.of(
                    spec.getSeason(),
                    spec.getPeriod(),
                    i,
                    spec.getRound(),
                    (byte) 0
            );
            List<ChampionRaceRecord> queryList = parent.queryRecords(querySpec);
            recordList.addAll(queryList);
        }
        return recordList;
    }

    private boolean handleQueuedTask() {
        ChampionRaceRecord recordTask;

        long startMs = System.currentTimeMillis();
        while ((recordTask = recordQueue.poll()) != null) {
            EcResult<Long> r = handleFightTask(recordTask);
            if (r.ok()) {
                if (r.data < currentPowerDiff) {
                    currentPowerDiff = r.data;
                    betRecord = recordTask;
                }
            }
            if (System.currentTimeMillis() - startMs > 500L) {
                break;
            }
        }
        if (recordQueue.isEmpty()) {
            setRunning(false);
        }
        return !isRunning();
    }

    private GameResult<Long> handleFightTask(ChampionRaceRecord recordTask) {
        ChampionRacePs psA = null, psB = null;
        if (StringUtils.hasLength(recordTask.getIdA())) {
            psA = parent.findPs(recordTask.getIdA());
        }
        if (StringUtils.hasLength(recordTask.getIdB())) {
            psB = parent.findPs(recordTask.getIdB());
        }
        GameResult<Long> r = parent.startFight(recordTask, psA, psB);
        if (!r.ok()) {
            return r;
        }
        ChampionRaceSpec spec = recordTask.getSpec();
        if (spec.getRound() < 3) {
            byte winner = recordTask.getWinner();
            ChampionRaceSpec nSpec = ChampionRaceSpec.of(
                    spec.getSeason(),
                    spec.getPeriod(),
                    spec.getGroup(),
                    (byte) (spec.getRound() + 1),
                    (byte) 0);
            byte nIndex = (spec.getRound() == 1)
                    ? (byte) (recordTask.getIndex() % 2 == 0 ? 1 : 0)
                    : (byte) (recordTask.getIndex() / 2);
            ChampionRaceRecord nRecord = nextRecordList.stream()
                    .filter(rd -> rd.getIndex() == nIndex && rd.getSpec().equals(nSpec))
                    .findAny()
                    .orElse(null);
            if (Objects.isNull(nRecord)) {
                nRecord = ChampionRaceRecord.of(nSpec, null, null);
                nRecord.setIndex(nIndex);
                nextRecordList.add(nRecord);
            }
            String wUid = (winner == GDFight.Team.A)
                    ? recordTask.getIdA()
                    : recordTask.getIdB();
            if (spec.getRound() == 1) {
                if (recordTask.getIndex() == 1 || recordTask.getIndex() == 2) {
                    nRecord.setIdA(wUid);
                } else {
                    nRecord.setIdB(wUid);
                }
            } else {
                if (recordTask.getIndex() % 2 == 0) {
                    nRecord.setIdA(wUid);
                } else {
                    nRecord.setIdB(wUid);
                }
            }
        }
        return r;
    }
}
